[Backport v8] Support wildcard values for content scope dimensions - #6292
Merged
Conversation
## Problem Content scopes could only grant access to concrete dimension values that are part of `availableContentScopes`. There was no way to grant a user access to any value of a single dimension (e.g. every language within a domain, or every product) without enumerating all values — which is not feasible for dimensions with many (potentially thousands) of values. ## Solution `getContentScopesForUser` can now use the wildcard value "*" as the value of a single content scope dimension to grant access to any value for that dimension. The wildcard is matched during the content scope check, so it does not need to be part of `availableContentScopes`. For users with access to all content scopes, `currentUser.permissions[].contentScopes` now returns a single wildcard scope instead of the enumerated `availableContentScopes`. The default `isAllowed` and `currentUser.allowedContentScopes` handle the wildcard; a custom `isAllowed` must treat "*" as matching any value of a dimension. (cherry picked from commit a00f0b2) Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B37BzfVeTSW2Kn9Qgvtd1v
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
fraxachun
approved these changes
Sep 7, 2026
VPS-Obi
approved these changes
Sep 7, 2026
VPS-thodax
disabled the stack merge
September 7, 2026 14:29
VPS-thodax
added a commit
that referenced
this pull request
Sep 8, 2026
) Backport of #6115 to `v8.x.x`. > [!NOTE] > This PR is stacked on #6292 (the backport of #6114 to `v8.x.x`, layer 1). It targets `claude/backport-v8-6114` because `v8.x.x` doesn't have the wildcard content scope dimension support (#6114) yet. Once #6292 is merged into `v8.x.x`, this PR's base will need to be retargeted to `v8.x.x` (or GitHub will do so automatically once #6292 merges, matching how the original stacked PRs behaved). ## Original description ### Problem Content scope dimensions were only known implicitly from the keys of the `availableContentScopes` values. An optional dimension that is not part of `availableContentScopes` (e.g. one with too many values to enumerate) therefore had no runtime representation at all — it could neither be declared nor used with arbitrary values. ### Solution Add an optional `availableContentScopeDimensions` option to the `UserPermissionsModule` to declare the content scope dimensions (with optional labels) at runtime. When omitted, the dimensions are derived from the keys of `availableContentScopes` as before, so existing apps are unaffected. The declared dimensions are used to represent access to all content scopes as a per-dimension wildcard (`{ domain: "*", ... }`), which therefore also covers dimensions that are not part of `availableContentScopes`. A content scope for a dimension that is not part of `availableContentScopes` may now hold any value (including the `"*"` wildcard). #### Removing `checkContentScopes` Content scopes are no longer validated against `availableContentScopes` (the `checkContentScopes` method is removed) — see the original PR (#6115) for the full rationale. ## Backport notes Cherry-picking the squash commit (`f4d091fa71ffe1c3c0f72431bbdb6151b6e93faa`) from `main` onto `claude/backport-v8-6114` produced conflicts in two files, both resolved by applying the incoming change against `v8.x.x`'s existing code: - `packages/api/cms-api/src/user-permissions/user-content-scopes.resolver.ts`: the incoming code used `userService.findUserOrThrow(userId)`, but `findUserOrThrow` doesn't exist on `v8.x.x` (it was introduced by a later, unrelated `main` commit). Kept using `v8.x.x`'s existing `userService.getUser(userId)` instead, combined with the new `filterContentScopesForUser` (already present via #6114's backport). - `demo/api/src/content-scope/content-scope.interface.ts`: module augmentation naming conflict (`@dextinity/cms-api` vs. `@comet/cms-api`, matching `v8.x.x`'s pre-rename package naming — see #6280 for precedent). Kept `@comet/cms-api` and added the new `product` dimension. Also converted the cherry-picked `user-permissions.service.spec.ts` from `vitest` to `jest` (matching `@comet/cms-api`'s test runner on this branch — same adjustment as #6144/#6280), and updated the changeset package name from `@dextinity/cms-api` to `@comet/cms-api` (per the pre-rename naming convention, per the routine's own caveat). ## Verification - `@comet/cms-api`: build, lint (prettier/eslint/tsc) pass. - `@comet/cms-api` full test suite: 204/204 passing, including the 7 new tests for `getAvailableContentScopeDimensions`/`filterContentScopesForUser`. - `demo/api`: `api-generator` regenerates cleanly with no diff to the generated files; lint (prettier/eslint/tsc) passes. - `demo/api` `AppModule`/`GraphQLModule` initialize correctly via `pnpm run console --help` (schema/block-meta regenerate); it only fails afterwards on connecting to Postgres, since the full Docker demo could not be started in this sandbox — Docker Hub image pulls are blocked by the environment's network policy (403 from CloudFront), consistent with the same limitation noted on prior v8 backport PRs (e.g. #6280, #6292). Please verify the runtime-declared content scope dimensions manually before merging. --- 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01DeZZCJgNydRxnbPuRBkTjp --- _Generated by [Claude Code](https://claude.ai/code/session_01DeZZCJgNydRxnbPuRBkTjp)_ Co-authored-by: Claude <noreply@anthropic.com>
VPS-thodax
added a commit
that referenced
this pull request
Sep 8, 2026
## Problem The release workflow on `v8.x.x` fails when assembling the release plan: > 🦋 error Error: Found changeset user-permissions-wildcard-content-scope for package @dextinity/cms-api which is not in the workspace No release can be published from `v8.x.x` until this is resolved. ## Cause `.changeset/user-permissions-wildcard-content-scope.md` was backported from a branch where the packages are already published under the `@dextinity/*` scope. On `v8.x.x` they still use `@comet/*`, so `@dextinity/cms-api` does not exist in the workspace and Changesets aborts. **This is the second time the same mistake blocks the v8 release, and it happened despite the backport routine explicitly warning about it.** #6293 fixed the identical break for `olive-pears-invent` less than a week ago. The routine carries a caveat about adjusting the changeset scope when backporting to `v8.x.x` — #6318 followed it and renamed its changeset, but #6292, which added this one, did not. A caveat in the prompt is evidently not enough: the routine needs a check that fails the backport when a changeset names a package that isn't in the target branch's workspace. ## Fix Rename the packages in the changeset's frontmatter to `@comet/cms-api` and `@comet/cms-admin`, matching the names in `packages/api/cms-api/package.json` and `packages/admin/cms-admin/package.json` on this branch. The changeset text is unchanged, so the released changelog entry stays the same. ## Verification `changeset status` cannot run on this branch (it resolves changed packages against a `main` base ref that doesn't apply here), so the release plan was assembled directly via `@changesets/get-release-plan`. It now succeeds and versions 19 packages from `8.31.0` to `8.32.0`, consuming both pending changesets. ## Further information - Failing run: https://github.com/vivid-planet/dextinity/actions/runs/34201879258 - Previous occurrence and fix: #6293 - Backport that added this changeset: #6292 (the sibling backport #6318 did rename its changeset) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_017d1A8MxYTpS29HTXgKJpJA --- _Generated by [Claude Code](https://claude.ai/code/session_017d1A8MxYTpS29HTXgKJpJA)_ Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Backport of #6114 to
v8.x.x.Original description
Problem
Content scopes could only grant access to concrete dimension values that are part of
availableContentScopes. There was no way to grant a user access to any value of a single dimension (e.g. every language within a domain, or every product) without enumerating all values — which is not feasible for dimensions with many (potentially thousands) of values.Solution
getContentScopesForUsercan now use the wildcard value"*"as the value of a single content scope dimension to grant access to any value for that dimension. The wildcard is matched during the content scope check, so it does not need to be part ofavailableContentScopes.For users with access to all content scopes,
currentUser.permissions[].contentScopesnow returns a single wildcard scope (e.g.[{ domain: "*", language: "*" }]) instead of the enumeratedavailableContentScopes. The defaultisAllowedandcurrentUser.allowedContentScopeshandle the wildcard; a customisAllowedmust treat"*"as matching any value of a dimension.Backport notes
Cherry-picking the squash commit (
a00f0b2ed6bed7a53b0aad6c5c31f41aa19e1f39) frommainproduced conflicts inpackages/api/cms-api/src/user-permissions/access-control.service.tsandpackages/api/cms-api/src/warnings/warning.resolver.ts, both resolved by applying the incoming change on top ofv8.x.x's existing code (an oldercheckContentScopehelper replaced by the newisScopeWithinhelper, and an import path difference from a laterentity-infodirectory move onmainthat isn't part ofv8.x.x).Verification
@comet/cms-apiand@comet/cms-admin: build, lint (prettier/eslint/tsc) pass.demo/api: lint (api-generator regeneration + prettier/eslint/tsc) passes, generated files unchanged.packages/api/cms-apiunit tests foraccess-control.servicepass.demo/apiAppModuleinitializes correctly viapnpm run console --help(schema/block-meta regenerate); it only fails afterwards on connecting to Postgres, since the full Docker demo could not be started in this sandbox — Docker Hub image pulls are blocked by the environment's network policy (403 from CloudFront).🤖 Generated with Claude Code
https://claude.ai/code/session_01B37BzfVeTSW2Kn9Qgvtd1v
Generated by Claude Code